/*
 * This file is part of ELCube.
 *
 * ELCube is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ELCube is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with ELCube.  If not, see <https://www.gnu.org/licenses/>.
 */
package cn.nkpro.elcube.bigdata.service.impl;

import cn.nkpro.elcube.bigdata.service.ElasticSearchService;
import cn.nkpro.elcube.co.query.DataQueryService;
import cn.nkpro.elcube.co.query.model.DataFieldDesc;
import cn.nkpro.elcube.co.query.model.DataQueryColumn;
import cn.nkpro.elcube.co.query.model.DataQueryRequest;
import cn.nkpro.elcube.co.query.model.DataQueryResponse;
import cn.nkpro.elcube.data.elasticearch.ESSqlRequest;
import cn.nkpro.elcube.data.elasticearch.ESSqlResponse;
import cn.nkpro.elcube.data.elasticearch.LimitQueryBuilder;
import cn.nkpro.elcube.data.elasticearch.SearchEngine;
import cn.nkpro.elcube.data.elasticearch.annotation.ESDocument;
import cn.nkpro.elcube.docengine.model.es.DocExtES;
import cn.nkpro.elcube.docengine.model.es.DocHES;
import cn.nkpro.elcube.docengine.service.NkDocPermService;
import cn.nkpro.elcube.exception.NkAccessDeniedException;
import cn.nkpro.elcube.security.SecurityUtilz;
import cn.nkpro.elcube.utils.BeanUtilz;
import com.alibaba.fastjson.JSONObject;
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public class ElasticSearchServiceImpl implements ElasticSearchService {

    @Autowired@SuppressWarnings("all")
    private SearchEngine searchEngine;
    @Autowired@SuppressWarnings("all")
    protected NkDocPermService docPermService;


    @Override
    public List<DataFieldDesc> getFieldCaps(String index){

        if(!SecurityUtilz.hasAnyAuthority("*:*","#*:READ","#"+index+":READ")){
            throw new NkAccessDeniedException(String.format("没有索引[%s]的访问权限", index));
        }

        FieldCapabilitiesResponse fieldCaps = searchEngine.getFieldCaps(index);

        return fieldCaps.get().values()
                .stream()
                .map(a-> a.values().stream().findFirst().orElse(null))
                .filter(Objects::nonNull)
                .filter(e->!e.getName().startsWith("_"))
                .filter(e->!e.getName().equals("$keyword"))
                .filter(e->!e.getType().equals("object"))
                .map(e-> BeanUtilz.copyFromObject(e,DataFieldDesc.class))
                .collect(Collectors.toList());
    }

    @Override
    public DataQueryResponse<Map<String, Object>> queryPage(DataQueryRequest request) {
        return queryList(request);
    }

    @Override
    public DataQueryResponse<Map<String, Object>> queryList(DataQueryRequest request) {

        DataQueryResponse<Map<String,Object>> response = null;

        for(String sql : request.getSqlList()) {

            String index = searchEngine.parseSqlIndex(sql);

            BoolQueryBuilder filterBuilder = QueryBuilders.boolQuery();

            //固定条件
            filterBuilder.must(new TermQueryBuilder("$",1));

            if (DocHES.class.getAnnotation(ESDocument.class).value().equals(index)||
                DocExtES.class.getAnnotation(ESDocument.class).value().equals(index)) {
                QueryBuilder builder = docPermService.buildDocFilter(NkDocPermService.MODE_READ, null, null, false);
                if(builder!=null)
                    filterBuilder.must(builder);
            } else {
                LimitQueryBuilder builder = docPermService.buildIndexFilter(index);
                if(builder!=null)
                    filterBuilder.must(builder);
            }

            if (request.getConditions() != null) {
                request.getConditions().forEach((k, v) -> filterBuilder.must(new LimitQueryBuilder((JSONObject) v)));
            }

            ESSqlResponse sqlResponse = searchEngine.sql(new ESSqlRequest(sql, request.getCursor(), request.getRows(), filterBuilder));

            if(sqlResponse.getColumns()==null&&request.getSqlColumns()!=null){
                sqlResponse.setColumns(request.getSqlColumns().stream()
                        .map(column -> BeanUtilz.copyFromObject(column, ESSqlResponse.Column.class))
                        .collect(Collectors.toList()));
            }

            if(response == null){
                List<DataQueryColumn> columns = sqlResponse.getColumns().stream()
                                .map(column -> BeanUtilz.copyFromObject(column, DataQueryColumn.class))
                                .collect(Collectors.toList());

                response = new DataQueryResponse<>(request.getSqlList(), columns, sqlResponse.transform().getList(),request.getRows(),sqlResponse.getCursor());
            }else{
                response.getList().addAll(sqlResponse.transform().getList());
            }
        }

        if(response!=null && request.getSqlList().size()>1){
            response.setCursor(null);
        }

        return response;
    }
}
